 /**************************************** 
 *  Submitted by:                         *
 *   Michael Fildstein, ID: 309161594     *
 *    Tomer Ben Rachel, ID: 021982475     *  
 *                                        * 
 *                                        * 
 *****************************************/   



  //This program draws what is known as the "Von Koch Curve" recursivley. It does this in these steps:
  //1.Finds the two points that divide the line into 3 sections of equal length
  //2.Finds the fifth point that is used to make the triangle or the tip that the line rises to:
  //3.Calculates the length of the side of the equilateral triangle
  //4.Calculates the middle of the bottom side of the triangle, meaning the side that is part of the initial line
  //5.Calculates the line which is called the height, that goes from the middle point we found to the fifth point
  //6.Calculates the angle that is between the two sides of the triangle that "looks at" the height we found
  //7.Determines whether the line goes left to right or right to left in order to know where to place the tip point
  //8.Using the angle we found earlier calculates the fifth point.

import java.awt.Color;


public class KochCurve {
	
	
	public static void main(String args[]) {
        Painter.draw("KochCurve");
    }
	
	public static void draw() { 
		Painter.setColor(Color.blue);
    	drawCurve(500,0 ,0 ,0 ,3);
	}
	
	//The function drawCurve draws the Von Koch curve recursively
	public static void drawCurve( double x1, double y1, double x2 , double y2, int depth ){
		double points [][] = findPoints(x1, y1, x2, y2);
		if (depth > 0){
			for (int i = 0 ; i < points.length - 1  ; i++){
				drawCurve(points[i][0], points[i][1], points[i + 1][0], points[i + 1][1], depth - 1);
			}	
		}else{
				Painter.drawLine((int)x1,(int)y1,(int)x2,(int)y2);
		}		
			
	}
	
   
  //The function findPoints receives two points as x and y coordinates and finds two other points which divide the line between 
  //the initial two points into three lines of equal length 
	public static double [][] findPoints ( double x1, double y1, double x2 , double y2){
		double points [][] = new double[5][2];
		points[0][0] = x1;                              //We place the points in a specific order inside the matrix to signfy their
		points[0][1] = y1;                              //location on the line from left(being index zero) to right
		points[1] = findPoints(1, 2, x1, y1, x2, y2);
		points[3] = findPoints(2, 1, x1, y1, x2, y2);
		points[4][0] = x2;
		points[4][1] = y2;
		double[] fifthElement = fifthElement(points);
		points[2][0] = fifthElement[0];
		points[2][1] = fifthElement[1];
		return points;
	}
	
	//The function fifthElement finds the tip point of the Equilateral triangle.
  //Returns that point 
	public static double[] fifthElement (double[][] points){
		double[] fifthElement = new double [2];
      
  //Calculates the length of a side of a triangular
		double sideOfTriangle = distanceBetweenTwoPoints(points[1][0], points[1][1], points[3][0], points[3][1]);  
    
   //Calculates the middle point in the side of the triangular.  
		double[] middlePoint = middlePoint(points[1][0], points[1][1], points[3][0], points[3][1]);	
  
  //Calculates the height of the Equilateral triangle.
 	double triangleHeight = sideOfTriangle * Math.sin(Math.PI/3);		
  //Calculates the angle in which the height of the triangle leans against the horizon				  
		double triangleHeightAngle = (slope(points[1][0], points[1][1], points[3][0], points[3][1])) - Math.PI/2;  									
		
		if (points[0][0] <= points[4][0]){			    //We want our point to be 'above' the given line.
																								//In order to find out which side is 'up'
																								//We check if our line goes left or right from the point of origin.
                                                                        
			fifthElement[0] = middlePoint[0] + triangleHeight * Math.cos(triangleHeightAngle);
			fifthElement[1] = middlePoint[1] + triangleHeight * Math.sin(triangleHeightAngle);
		}else{
			fifthElement[0] = middlePoint[0] - triangleHeight * Math.cos(triangleHeightAngle);
			fifthElement[1] = middlePoint[1] - triangleHeight * Math.sin(triangleHeightAngle);
		}
		
		return fifthElement;
	}
	
	//The function distanceBetweenTwoPoints calculates the distance between 2 given points
  //Returns the distance 
	public static double distanceBetweenTwoPoints (double x1, double y1, double x2 , double y2){
		double distance = Math.sqrt(Math.pow((x2 - x1), 2) + Math.pow((y2 - y1), 2));
		return distance;
	}
	
	//The function middlePoint calculates a coordinate which is exactly between two given points
  //Returns the middle point it finds 
	public static double[] middlePoint (double x1, double y1, double x2 , double y2){
		double[] middlePoint = new double [2];
		middlePoint[0] = (x1 + x2)/2;
		middlePoint[1] = (y1 + y2)/2;
		return middlePoint;
	}
   
   
	//The function slope calculates the slope of a line using 2 points.
  //Returns the slope
	public static double slope (double x1, double y1, double x2 , double y2){
		double slope = (y2 - y1)/(x2 - x1);
		double angle = Math.atan(slope);
		return angle;
	}
		
	//The function findPoints finds a point that divides a line in the ratio of (ratioA : ratioB)
  //Returns that point 
		public static double[] findPoints (int ratioA , int ratioB , double x1 , double y1 , double x2 , double y2){
			double[] newPoints = new double[2];
			newPoints[0] = ((ratioB * x1) + (ratioA * x2))/(ratioA +ratioB);
			newPoints[1] = ((ratioB * y1) + (ratioA * y2))/(ratioA +ratioB);
			return newPoints;
		}
	
		
}
